#pragma once

#include "jstr.h"
#include "jtype.h"

#include <jni.h>
#include <map>
#include <string>

namespace gtl
{

namespace jni
{

class jcls
{
public:
	jcls(JNIEnv* env, const char* clsName)
	{
		m_env = env;
		if(m_env == NULL)
			return;

		m_jcls = m_env->FindClass(clsName);
		if(m_jcls == NULL)
			return;

		m_jobj = m_env->AllocObject(m_jcls);
	}

	jcls(JNIEnv* env, const char* clsName, jobject jobj)
	{
		m_env = env;
		if(m_env == NULL)
			return;

		m_jobj = jobj;
		m_jcls = m_env->FindClass(clsName);
	}

	~jcls()
	{
	}

public:
	template<class T, class V>
	jcls& field(const char* name, V val)
	{
		if(m_env == NULL || m_jcls == NULL)
			return *this;

		jfieldID jfid = m_env->GetFieldID(m_jcls, name, jtype<T>::ty());
		if(jfid == NULL)
			return *this;

		setValue(jfid, val);
		m_fields[name] = jfid;
		return *this;
	}

	template<class T>
	T field(const char* name)
	{
		T val = 0;
		if(m_env == NULL || m_jcls == NULL)
			return val;

		jfieldID jfid = m_env->GetFieldID(m_jcls, name, jtype<T>::ty());
		if(jfid == NULL)
			return val;

		getValue(jfid, val);
		return val;
	}

public:
	jobject obj()
	{
		return m_jobj;
	}

	operator jobject()
	{
		return m_jobj;
	}

protected:
	void setValue(jfieldID jfid, int val)
	{
		m_env->SetIntField(m_jobj, jfid, val);
	}

	void setValue(jfieldID jfid, bool val)
	{
		m_env->SetBooleanField(m_jobj, jfid, val);
	}

	void setValue(jfieldID jfid, const char* val)
	{
		if(val == NULL)
			val = "";

		jstr jval(m_env, val, false);
		m_env->SetObjectField(m_jobj, jfid, jval);
	}

	void setValue(jfieldID jfid, const std::string& val)
	{
		setValue(jfid, val.c_str());
	}

	void getValue(jfieldID jfid, int& val)
	{
		val = m_env->GetIntField(m_jobj, jfid);
	}

	void getValue(jfieldID jfid, bool& val)
	{
		val = m_env->GetBooleanField(m_jobj, jfid);
	}

	void getValue(jfieldID jfid, const char*& val)
	{
		jobject jobj = m_env->GetObjectField(m_jobj, jfid);
		val = m_env->GetStringUTFChars((jstring)jobj, NULL);
	}

protected:
	JNIEnv* m_env;
	jclass m_jcls;
	jobject m_jobj;
	std::map<std::string, jfieldID> m_fields;
};

} // end of namespace jni

} // end of namespace gtl
